#include "qtcpdrive.h"
#include "../../lib/shared/qdriveattribute.h"
#include "../../lib/shared/qdrivevaluemap.h"
#include "../../lib/shared/qdrivemission.h"

#include <QHostAddress>

QTcpDrive::QTcpDrive(QObject *parent):
    QAbstractDrive(parent),
    m_tcpSocket(NULL)
{
    initAttribute();
}

QString QTcpDrive::name()
{
    return "TCP_Modbus";
}

bool QTcpDrive::addDriveMission(QDriveMission *mission)
{
    return QAbstractDrive::addDriveMission(mission);
}

void QTcpDrive::initAttribute()
{
    QDriveAttribute *attr;

    attr=new QDriveStringAttribute("IP Address");
    attr->setValue("192.168.1.1");
    appendAttribute(attr);

    attr=new QDriveNumberAttribute("IP Port");
    attr->setValue("10000");
    appendAttribute(attr);

    QHeaderInfo *info;
    info=new QHeaderInfo("Device Address");
    info->setProperty("type","int");
    info->setProperty("Min","1");
    info->setProperty("Max","246");
    info->setProperty("default_value","1");
    m_valueMap->insertHeader(0,info);
}


bool lessThan(const QPoint &pt1, const QPoint &pt2)
{
    return pt1.y()<pt2.y();
}

void QTcpDrive::initMission()
{
    QList<QStringList> values=m_valueMap->values();
    QMap<int,QList<QPoint> >    device[2];

    int d=m_valueMap->column("Device Address");
    int v=m_valueMap->column("Value Address");
    int type=m_valueMap->column("Type");
    int pro=m_valueMap->column("Period(s)");
    int lvl=m_valueMap->column("Level");
    int dd;

    int s=0;
    foreach(QStringList l,values)
    {
        dd=l.at(d).toInt();
        QPoint pt;
        pt.setX(s);
        pt.setY(l.at(v).toInt());
        if(l.at(type)=="Cycle")
        {
            QList<QPoint> p=device[0].value(dd);
            p.append(pt);
            device[0].insert(dd,p);
        }
        else
        {
            QList<QPoint> p=device[1].value(dd);
            p.append(pt);
            device[1].insert(dd,p);
        }
        s++;
    }
    for(int i=0;i<2;i++)
    {
        QMapIterator<int,QList<QPoint> > it(device[i]);
        QDriveMission *ms;


        while(it.hasNext())
        {
            it.next();
            QList<QPoint> p=it.value();
            if(p.size()==0)
            {
                continue;
            }
            qSort(p.begin(),p.end(),lessThan);
            int start;
            int end;
            start=end=p.first().y();
            int period=100000;
            int level=10000;
            int temp;
            QPoint point(65536,65536);
            p.append(point);
            foreach(QPoint pp,p)
            {

                if(pp.y()-start<16)
                {
                    end=pp.y();
                    temp=values.at(pp.x()).at(pro).toInt();
                    if(temp<period)
                    {
                        period=temp;
                    }
                    temp=values.at(pp.x()).at(lvl).toInt();
                    if(temp<level)
                    {
                        level=temp;
                    }
                }
                else
                {
                    ms=new QDriveMission;
                    ms->setValueAdress(start);
                    ms->setDataLengh(end-start+1);
                    ms->setDeviceAdress(it.key());
                    ms->setLevel(level);
                    ms->setPeriod(period);
                    ms->setType(i==0?MT_CYCLE:MT_TEMP);
                    ms->setMissionID((start<<16)+((end-start+1)<<8)+level);
                    if(!addDriveMission(ms))
                    {
                        delete ms;
                    }
                    period=10000;
                    level=10000;
                    start=end=pp.y();
                }
            }
        }
    }
}

void QTcpDrive::initConnect()
{
    if(m_tcpSocket!=NULL)
    {
        delete m_tcpSocket;
        m_tcpSocket=NULL;
    }
    m_tcpSocket=new QTcpSocket(this);

    QString ip=attribute("IP Address")->valueText();
    int port=attribute("IP Port")->value().toInt();

    m_tcpSocket->connectToHost(QHostAddress(ip),port);

    m_device=m_tcpSocket;
    connect(m_tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(state(QAbstractSocket::SocketState)));
}

void QTcpDrive::state(QAbstractSocket::SocketState s)
{
    stateChanged((int)s);
}

void QTcpDrive::releaseConnect()
{
    if(m_tcpSocket!=NULL)
    {
        delete m_tcpSocket;
        m_tcpSocket=NULL;
    }
    m_device=NULL;
}

QByteArray QTcpDrive::getSendData(QDriveMission *ms)
{
    QByteArray array;
    if(ms->missionCammand()==MC_READ)
    {
        array.resize(8);
        array[0]=ms->deviceAddress();
        array[1]=3;
        array[2]=(ms->valueAddress()>>8)&0xff;
        array[3]=ms->valueAddress()&0xff;
        array[4]=(ms->dataLengh()>>8)&0xff;
        array[5]=ms->dataLengh()&0xff;
        int crc=CRC_Value(array,6);
        array[6]=(crc>>8)&0xff;
        array[7]=crc&0xff;
        ms->setAttribute("Recv_Lengh",QString::number(5+2*ms->dataLengh()));
    }
    return array;
}

void QTcpDrive::analyseData(const QByteArray &data)
{
    if(m_currentMission==NULL)
    {
        m_data.clear();
        return;
    }
    m_data+=data;
    if((m_data[0]&0xff)!=m_currentMission->deviceAddress())
    {
        m_data.clear();
        m_currentMission->setFailedCode(102);
        m_data.clear();
        missionDone(m_currentMission);
        return;
    }
    if(m_data.at(1)&0x80)
    {

        if(m_data.size()==5)
        {
            int crc=CRC_Value(m_data,m_data.size()-2);
            if(((crc>>8)&0xff)==(m_data[3]&0xff) && (crc&0xff)==(m_data[4]&0xff))
            {
                m_currentMission->setFailedCode(m_data[2]&0xff);
            }
            else
            {
                m_currentMission->setFailedCode(100);
            }
            m_data.clear();
            missionDone(m_currentMission);
            return;
        }
        else if(m_data.size()>5)
        {
            m_currentMission->setFailedCode(101);
            m_data.clear();
            missionDone(m_currentMission);
            return;
        }
    }
    else
    {
        if(m_data.size()==m_currentMission->attribute("Recv_Lengh").toInt())
        {
            int crc=CRC_Value(m_data,m_data.size()-2);

            if(((crc>>8)&0xff)!=(m_data[m_data.size()-2]&0xff) || (crc&0xff)!=(m_data[m_data.size()-1]&0xff))
            {
                m_currentMission->setFailedCode(100);
            }
            else
            {
                if(m_currentMission->missionCammand()==MC_READ)
                {
                    ushort us[128]={0};
                    for(int i=0;i<m_data.size()-5;i++)
                    {

                        us[i]=((m_data[3+i*2]<<8)&0xff00)+(m_data[4+2*i]&0xff);
                    }
                    m_currentMission->setData(us,128);

                }
            }
            m_data.clear();
            missionDone(m_currentMission);
            return;
        }
    }    
}
